#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/wait.h>
#include<sys/types.h>

#define SIZE 32
#define NUM 1024
#define SEP " "

//保存完整指令
char cmd_line[NUM];

//保存分隔后的每个指令
char* g_argv[SIZE];

int main()
{
  //命令行解析器一定是常驻进程，永远不退出
  while(1)
  {
    //1.打印提示信息
    printf("[yly@localhost myshell]#");
    //没有\n，不会自动刷新缓冲区
    fflush(stdout);
    memset(cmd_line,'\0',sizeof cmd_line);
    
    //2.获取用户输入的指令
    while(fgets(cmd_line, sizeof cmd_line, stdin) == NULL)
    {
      continue; 
    }
    //用户输入完指令之后会敲一个\n，但是这个\n会被当成字符输入到cmd_line中
    cmd_line[strlen(cmd_line) - 1] = '\0';

    //3.命令行字符串解析，strtok函数
    g_argv[0] = strtok(cmd_line, SEP);//strtok函数在第一次调用的时候需要传原始字符串，之后再次调用时直接传NULL就默认使用上次使用的字符串了
    int index = 1;
    if(strcmp(g_argv[0], "ls") == 0)
    {
      g_argv[index++] = "--color=auto";
    }
    while(g_argv[index++] = strtok(NULL, SEP));
    //for(index = 0; g_argv[index]; ++index)
    //{
    //  printf("g_argv[%d] = %s\n", index, g_argv[index]);
    //}
    
    //4.TODO 内置命令--让父进程（shell）自己执行的命令，也叫内建命令
    if(strcmp(g_argv[0], "cd") == 0)
    {
      if(g_argv[1] != NULL)
      {
        chdir(g_argv[1]);//直接切换到指定目录

        continue;
      }
    }
    
    //5.子进程处理指令
    pid_t pid = fork();
    if(pid == 0)
    {
      //使用execvp是因为v直接传数组就可以，在环境变量中p可以直接调用
      execvp(g_argv[0],g_argv);
    }
    //father
    int status = 0;
    pid_t ret = waitpid(pid, &status, 0);
    if(ret > 0)
    {
      printf("exit code: %d\n", WEXITSTATUS(status));
    }

  }
  return 0;
}
